/*
** File: hey_format.c
** Desc: Reading & formatting functions for 'hey'
** Auth: Cian Synnott <pooka@redbrick.dcu.ie>
** Date: Sun Nov 15 19:56:51 GMT 1998
**
** $Id: hey_format.c,v 1.3 2003-08-11 01:21:45 c-hey Exp $
*/

#include <stdarg.h>
#include <string.h>
#include <stdio.h>

#include "hey_format.h"
#include "hey_readline.h"
#include "dyn_page.h"
#include "config.h"
#include "aux.h"

#ifdef HAVE_LIBREADLINE
/* <bobb> readline includes */
#include <readline/readline.h>
#include <readline/history.h>
#endif

#define LINESIZE 128

/* Buffer to keep things in */
dyn_page *hey_page = NULL;

/* Read user input into hey_page, also allocates it & suchlike */ 
void hey_user_input(void) {
	char *ptr;
	char *line;


	/* Allocate hey_page, passing hey_wrap as the word wrapping width */
	if (!(hey_page = dyn_pageAlloc(hey_wrap))) 
		printerr_exit ("Woah. Error allocating hey_page.\n");


	/* we are editing now */
	hey_readline_init();

	while ((line = hey_readline())){

		/* Clean up whitespace */
		for (ptr = line; *ptr; ptr++) 
			switch (*ptr) {
				case '\t':
				case '\f':
				case '\r':
				case '\n':
					*ptr = ' ';
			}
			
		/* Append line to page */
		if(!(dyn_pageAppend(hey_page, line))){
			printerr_exit("Realloc failure from dyn_pageAppend in hey_page.\n");
		}
	}

	hey_readline_fini();

	/* And that's that ... */
	return;

}

/* Prototype for strprint(); see below ... */
char *strprint(char *, int, char *, ...);

/* Formats the lines present in hey_page into the 'hey' to be sent. */
void hey_format_input(void) {
	dyn_page *new_format;
	char line[LINESIZE];
	char *ptr;
	int offset, topwidth, btnwidth, width;

	if(strlen(hey_title) > strlen(hey_footer)) {
		width = strlen(hey_title) + 2;
	} else {
		width = strlen(hey_footer) + 2;
	}
	
	/* Calculate the width of the hey .. It's either the strlen (hey_title) 
	** + 2 (spaces on either side), or the longest string in hey_page
	** Then add 4 for the space on either side of the message & 
	** the side border chars */
	if(!(ptr = dyn_pageRead(hey_page))) return;

	do {
		if (strlen(ptr) > width) width = strlen(ptr);
	} while ((ptr = dyn_pageRead(NULL)));
	
	width += 4;
	
	/* Set up the offset to print before each line (thus centering it ...) */
	offset = ((80 - width) / 2);

	/* Allocate the new page, with no wrapping width */
	if (!(new_format = dyn_pageAlloc(0))) 
		printerr_exit("Woah. Error allocating formatted page.\n");

	/* Print top line into it */
	if (!strlen(hey_title)) 
		strprint(line, LINESIZE, "%xc%c%xc%c", 
				' ', offset, B_TOPLFT, B_TOP, width - 2, B_TOPRHT);
	else {
		/* The total number of 'top' border chars we'll have to print is the
		** the width minus two chars for the corners, two chars for the spaces 
		** either side of the title, and the length of the title itself */
		topwidth = width - 4 - strlen(hey_title);
		strprint(line, LINESIZE, "%xc%c%xc %s %xc%c", 
				' ', offset, B_TOPLFT, 
				B_TOP, topwidth / 2, 
				hey_title,
				B_TOP, topwidth - (topwidth / 2), 
				B_TOPRHT);
	}

	dyn_pageAppend(new_format, line);
	
	/* Print all the other lines into it */
	if(!(ptr = dyn_pageRead(hey_page))) return;

	do {
		/* Format the line & append to new page */
		strprint(line, LINESIZE, 
				"%xc%c %s%xc%c", ' ', offset, B_LFT, ptr, 
				' ', width - 3 - strlen(ptr), B_RHT);
		dyn_pageAppend(new_format, line);

	} while ((ptr = dyn_pageRead(NULL)));

	/* now for the footer */
	if(!strlen(hey_footer)) 
		strprint(line, LINESIZE, "%xc%c%xc%c", 
             ' ', offset, B_BOTLFT, B_BOT, width - 2, B_BOTRHT);
	else {
		btnwidth = width - 4 - strlen(hey_footer);
		strprint(line, LINESIZE, "%xc%c%xc %s %xc%c",
				' ', offset, B_BOTLFT, B_BOT, btnwidth / 2, 
				hey_footer, B_BOT, btnwidth - (btnwidth / 2),
				B_BOTRHT);
	}

	dyn_pageAppend(new_format, line);

	/* Free the old hey_page, and point at the new formatted one */
	dyn_pageFree(hey_page);
	hey_page = new_format;

	return;
}

/* A little like a stripped-down version of snprintf. Accepts only string and
** character arguments, and only one modifier - x, meaning that the argument
** after the string or char will be the number of times to repeat it. */
char *strprint(char *str, int size, char *fmt, ...) {
	char *str_p, *fmt_p, *str_arg, char_arg;
	va_list args;
	int multiple;

	/* Clear the string and setup the va_* macros */
	memset(str, 0, size);
	va_start(args, fmt);

	str_p = str;
	fmt_p = fmt;

	/* Cycle through the format string */
	while (*fmt_p && (str_p - str) < size) {
		if (*fmt_p == '%') {	
			multiple = 1; 
			char_arg = 0; 
			str_arg  = 0;

			fmt_p++;
			switch (*fmt_p) {
				case 'c': 
					char_arg = (char)va_arg(args, int);
					break;
				
				case 's': 
					str_arg = va_arg(args, char *); 
					break;
			
				case 'x': 
					fmt_p++; 
					if (*fmt_p == 'c') char_arg = (char)va_arg(args, int); 
					if (*fmt_p == 's') str_arg  = va_arg(args, char *);
					multiple = va_arg(args, int);
					break;
				
				default:
					return NULL;
			}
			fmt_p++; 

			/* Concat the char or string arg onto the end of str 'multiple' 
			** times */
			while (multiple && (str_p - str) < size - 1) {	
				if (str_arg) {
					strncat(str, str_arg, size - strlen(str) - 1);
					str_p += strlen(str_arg);
				} else if (char_arg) {
					*str_p = char_arg;
					str_p++;
				}
				multiple--;
			}
		} else {
			*str_p = *fmt_p;
			str_p++, fmt_p++;
		}

	}

	/* Set the last character to 0 if necessary */
	if ((str_p - str) >= size) str[size - 1] = 0;
					
	/* Finish & return */
	va_end(args);
	return str;
}
